<template>
  <span class="x-countdown">
    <slot :time="time" :day="timeData.day" :hour="timeData.hour" :minute="timeData.minute" :second="timeData.second" />
  </span>
</template>

<script lang="ts">
  import { defineComponent, reactive, toRefs, onUnmounted } from 'vue'

  export default defineComponent({
    name: 'XCountdown',
    components: {},
    props: {
      end: {
        type: [String, Number],
        default: 0
      },
      // 倒计时时长（单位：毫秒）
      time: {
        type: [String, Number],
        default: 0
      },
      // 是否自动
      auto: {
        type: Boolean,
        default: true
      }
    },
    emits: ['update', 'finish'],
    setup($props, { emit: $emit }) {
      const $state: any = reactive({
        timer: null,
        timeData: {
          remain: 0,
          day: null,
          hour: null,
          minute: null,
          second: null
        }
      })

      // 个位补0
      const repairZero = (val: number) => {
        return ('0' + String(val)).substr(-2)
      }

      // 更新时间
      const updateTimeData = () => {
        let t = $state.timeData.remain
        $state.timeData = {
          ...$state.timeData,
          day: Math.floor(t / 1000 / 60 / 60 / 24),
          hour: repairZero(Math.floor((t / 1000 / 60 / 60) % 24)),
          minute: repairZero(Math.floor((t / 1000 / 60) % 60)),
          second: repairZero(Math.floor((t / 1000) % 60))
        }
        // console.log($state.timeData)
        $emit('update', $state.timeData)
      }

      // 停止计时倒计时
      const pause = () => {
        if ($state.timer) {
          clearTimeout($state.timer)
          $state.timer = null
        }
      }

      // 定时器
      const startTimer = () => {
        const { remain } = $state.timeData
        if ($state.timer) {
          clearTimeout($state.timer)
        }
        if (remain > 0) {
          $state.timer = setTimeout(() => {
            $state.timeData.remain -= 1000
            updateTimeData()
            if (remain <= 0) {
              pause()
              $emit('finish')
            } else {
              startTimer()
            }
          }, 1000)
        } else {
          $emit('finish')
        }
      }

      // 开始倒计时
      const start = () => {
        if (!$state.timer) {
          startTimer()
        }
      }

      // 初始化倒计时
      const reset = () => {
        let time = $props.end
        if (time) {
          let date
          if (typeof time === 'object') {
            date = time
          } else {
            if (typeof time === 'string') {
              if (/^\d+$/.test(time)) {
                time = parseInt(time)
              } else {
                time = time.replace(/\-/gi, '/')
              }
            }
            if (typeof time === 'number' && time.toString().length === 10) {
              time = time * 1000
            }
            date = new Date(time)
          }

          const remain = +new Date(date) - +new Date()
          if (remain >= 0) {
            $state.timeData.remain = remain
          }
        } else if ($props.time) {
          $state.timeData.remain = Number($props.time)
        }
        updateTimeData()
        if ($props.auto) {
          start()
        }
      }
      reset()

      // 卸载组件实例后调用
      onUnmounted(() => {
        pause()
      })

      return {
        ...toRefs($state)
      }
    }
  })
</script>

<style></style>
